<template>
  <div class="role-menu">
    <unfold>
      <!-- 左侧角色列表 -->
      <template v-slot:tree-list>
        <div class="left box">

          <!-- header -->
          <div class="box-header bg-primary text-white text-weight-regular flex items-center">
            <q-icon name="iconfont icontubiao-33" color="white" class="q-mr-sm" />
            <div class="head-title vertical-middle user-select-none">角色列表</div>
          </div>

          <!-- 列表 -->
          <q-scroll-area class="box-content bg-white" :thumb-style="CommonConfig.thumbStyle">
            <q-list style="min-width: 100px;">
              <div v-for="role in roles" :key="role.id">
                <q-item
                  class="role-item"
                  :active="selectedRoleId === role.id"
                  active-class="activated"
                  @click="onRoleClick(role.id)"
                  clickable
                  v-ripple
                >
                  <q-item-section>{{ role.name }}</q-item-section>
                </q-item>
                <q-separator />
              </div>
            </q-list>
          </q-scroll-area>
        </div>
      </template>

      <!-- 右侧 card -->
      <template v-slot:content>
        <div class="right box">
          <div class="relative-position page-content full-height padding-b-20 padding-t-20"
               style="padding-left: 20px;padding-right: 20px">

            <!-- 内容 -->
            <q-tabs
              v-model="tab"
              inline-label
              active-color="primary"
              align="left"
            >
              <q-tab name="pc" icon="iconfont icontubiao-30" label="PC 端权限" v-stat="{id:'dlp010201',name:'pc端界面'}" />
              <q-tab name="mobile" icon="iconfont icontubiao-1" label="手机端权限" v-stat="{id:'dlp010202',name:'手机端界面'}" />
              <!--<q-tab name="pad" icon="iconfont icontubiao-32" label="工位 Pad" />-->
<!--              <q-tab name="board" icon="iconfont icontubiao-31" label="现场看板" />-->
              <q-space></q-space>
              <q-btn style="width: 96px; min-height: 32px; padding: 0 16px" class="btn" label="保存" color="primary" @click="savePermissions()" :loading="saveLoading" />
            </q-tabs>

            <q-separator style="flex: none;" />

            <!--<q-scroll-area class="box-content q-pa-md" :thumb-style="CommonConfig.thumbStyle">-->
            <q-table
              class="scroll myTable-line no-margin padding-t-20 flex-1 stick-last-col"
              :columns="tableColumns"
              :data="menus"
              row-key="id"
              :loading="isTableLoading"
              :hide-bottom="!!menus.length"
              :pagination="{ rowsPerPage: 0 }"
            >
              <template v-slot:header-cell-type="props">
                <q-th :props="props">
                  <div class="flex items-center" style="width: 100px">
                    <div>{{ props.col.label }}</div>
                    <tips v-if="tab === 'pc'" tips="目录指导航栏中的一级模块；菜单指导航栏中的二级模块；标签页指页面最上方的标签页；按钮指页面中的按钮" class="margin-l-10"/>
                    <tips v-else tips="目录指手机端首页的功能模块，功能指各模块中的具体功能点" class="margin-l-10"/>
                  </div>
                </q-th>
              </template>
              <template v-slot:header-cell-roleDataItem="props">
                <q-th :props="props">
                  <div class="flex items-center">
                    <div>{{ props.col.label }}</div>
                    <tips tips="数据权限决定了用户可看到多大组织范围内的数据" class="margin-l-10"/>
                  </div>
                </q-th>
              </template>
              <template v-slot:header-cell-businessScope="props">
                <q-th :props="props">
                  <div class="flex items-center" style="width: 100px">
                    <div>{{ props.col.label }}</div>
                    <tips tips="可选择看到所选组织范围的全部或个人数据" class="margin-l-10"/>
                  </div>
                </q-th>
              </template>
              <template v-slot:body="props">
                <transition name="fade">
                  <q-tr :props="props" v-show="props.row.show" :style="!props.row.isChecked && { color: '#999' }">
                    <q-td
                      key="name"
                      :props="props"
                      :style="{ 'padding-left': props.row.level * 20 + 16 + 'px' }"
                    >
                      <q-btn
                        :class="{ 'invisible': props.row.childrenCount < 1 }"
                        dense round flat
                        :icon="props.row.expand ? 'iconfont icontubiao-40' :
                            'iconfont icontubiao-43'"
                        @click="toggleExpansion(props.row)"
                      />
                      {{ props.row.name }}
                    </q-td>
                    <q-td key="type" :props="props">
                      {{ props.row.type }}
                    </q-td>
                    <q-td key="roleDataItem" :props="props">
                      <div style="width: 200px;" class="text-ellipsis">{{props.row.isAll ? '全部' : (props.row.roleDataItem || '--')}}
                        <q-tooltip>{{props.row.isAll ? '全部' : (props.row.roleDataItem || '--')}}</q-tooltip>
                      </div>
                    </q-td>
                    <q-td key="businessScope" :props="props" style="width: 110px;">
                      <div v-if="props.row.isBusiness">
                        <!--<span>个人</span>-->
                        <!--<q-toggle-->
                          <!--:true-value="props.row.trueVal"-->
                          <!--:false-value="props.row.falseVal"-->
                          <!--v-model="props.row.isAll"-->
                        <!--/>-->
                        <!--<span>全部</span>-->
<!--                        <customized-switch-->
<!--                          style="width: 100px; height: 24px"-->
<!--                         :options="props.row.businessAuthorityOpt"-->
<!--                         v-model="props.row.businessAuthority"-->
<!--                        />-->
                        {{props.row.businessAuthorityOpt.find(v=>v.value === props.row.businessAuthority) ? props.row.businessAuthorityOpt.find(v=>v.value === props.row.businessAuthority).label : '--'}}
                      </div>
                      <span v-else>--</span>
                    </q-td>
                    <q-td key="operation" :props="props" style="width: 150px;" >
                      <q-btn round icon="iconfont iconshezhitubiao" color="primary" flat @click.stop="onSetRole(props.row)" :disable="props.row.isBusiness ? false : !setOptions.includes(props.row.menuId)"><q-tooltip>设置</q-tooltip></q-btn>
                      <q-toggle
                        size="xs"
                        v-model="props.row.isChecked"
                        @input="onMenuToggle(props.row)"
                      />
                    </q-td>
                  </q-tr>
                </transition>
              </template>
            </q-table>
            <!--</q-scroll-area>-->
          </div>
        </div>
      </template>
    </unfold>
    <role-set-dialog :show="isShowRoleSetDialog" @close="isShowRoleSetDialog = false; listMenus()" :roleDataDialog="roleDataDialog" :tab="tab" :roleId="selectedRoleId" :setOptions="setOptions"/>
  </div>
</template>

<script>
import roleDefineApi from 'src/boot/system/role-define'
import roleMenuApi, { getRoleData } from 'src/boot/system/role-menu'
import Unfold from 'src/components/unfold'
import { mapGetters } from 'vuex'
// import CustomizedSwitch from 'src/components/customized-switch'
import statMixin from '../../assets/js/stat-mixin'
import _ from 'lodash'
import RoleSetDialog from './role-set-dialog'
export default {
  name: 'role-menu',
  mixins: [statMixin],
  components: {
    RoleSetDialog,
    Unfold
  },
  computed: {
    ...mapGetters([
      'userInfo'
    ]),
    setOptions () {
      return this.tab === 'pc' ? this.pcOptions : this.mobileOptions
    }
  },
  // // 注入刷新视图方法
  // inject: ['reload'],
  data () {
    return {
      // 表格列
      tableColumns: [
        { name: 'name', label: '名称', align: 'left' },
        { name: 'type', label: '类型', align: 'left' },
        { name: 'roleDataItem', label: '数据权限', align: 'left' },
        { name: 'businessScope', label: '业务范围', align: 'center' },
        { name: 'operation', label: '操作', align: 'center' }
      ],
      isShowRoleSetDialog: false,
      roleDataDialog: {},
      // 表格正在加载
      isTableLoading: false,

      // 保存按钮正在加载
      saveLoading: false,

      // 角色
      roles: [],
      //
      roleMenuData: {},
      // 选择的角色
      selectedRoleId: null,

      // 菜单
      menus: [],
      // 4）哪些页面可设置数据权限-PC（具体说明请见“数据权限说明”页面）：
      //   b、DNC：文件传输
      //   c、生产执行：计划派工、加工工单、质检工单
      //   e、刀具管理：在用刀具寿命
      // 5）哪些页面可设置数据权限-app（具体说明请见“数据权限说明”页面）：
      //   a、加工工单、质检工单
      //   c、停机填报
      //   d、文件传输
      pcOptions: [93, 76, 57, 64, 103],
      mobileOptions: [2, 10, 31, 35],
      // 选中的 tab
      tab: 'pc',
      // pc业务权限
      pcBusinessAuthority: [
        {
          page: this.Enums.SYS_PERMISSION.WORK_ORDER_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_WORK_ORDERS,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_WORK_ORDERS
        }, // 加工工单
        {
          page: this.Enums.SYS_PERMISSION.QC_ORDER_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_QC_ORDERS,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_QC_ORDERS
        }, // 质检工单
        {
          page: this.Enums.SYS_PERMISSION.MAINTENANCE_ORDER_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_MAINTENANCE,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_MAINTENANCE
        }, // 保养工单
        {
          page: this.Enums.SYS_PERMISSION.G_GOV_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_G_CODE,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_G_CODE
        }, // G代码管理
        {
          page: this.Enums.SYS_PERMISSION.APPLY_REPAIR_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_APPLY_REPAIR,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_APPLY_REPAIR
        }, // 维修申请
        {
          page: this.Enums.SYS_PERMISSION.FiX_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_REPAIR,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_REPAIR
        }, // 维修工单
        {
          page: this.Enums.SYS_PERMISSION.APPLY_OUTSOURCING_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_OUTSOURCING,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_OUTSOURCING
        }, // 委外工单
        {
          page: this.Enums.SYS_PERMISSION.CUTTER_TOOLREVIEW_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_CUTTER_APPROVAL_LIST,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_CUTTER_APPROVAL_LIST
        }, // 刀具审核
        // {
        //   page: this.Enums.SYS_PERMISSION.APPLY_USE_PAGE.value,
        //   all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_STOCK_APPLY_LIST,
        //   owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_STOCK_APPLY_LIST
        // }, // 领用申请
        {
          page: this.Enums.SYS_PERMISSION.TOOLMONITORING_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_STOCK_WORKSHOP_LIST,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_STOCK_WORKSHOP_LIST
        } // 工具监控
      ],
      // 手机业务权限
      mBusinessAuthority: [
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.WORK_ORDER.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_ALL_WORK_ORDERS,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_OWNED_WORK_ORDERS
        }, // 加工工单
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.QC_ORDER.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_ALL_QC_ORDERS,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_OWNED_QC_ORDERS
        }, // 质检工单
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.MAINTENANCE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_ALL_MAINTENANCE,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_OWNED_MAINTENANCE
        }, // 保养工单
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.APPLY_REPAIR.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_ALL_APPLY_REPAIR,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_OWNED_APPLY_REPAIR
        }, // 维修申请
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.FiX_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_ALL_REPAIR,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_OWNED_REPAIR
        }, // 维修工单
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.APPLY_OUTSOURCING.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_ALL_OUTSOURCING,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_MOBILE.READ_OWNED_OUTSOURCING
        }, // 委外工单
        {
          page: this.Enums.SYS_PERMISSIONS_MOBILE.APPLY_USE_PAGE.value,
          all: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_ALL_STOCK_APPLY_LIST,
          owned: this.Enums.SYS_BUSINESS_PERMISSIONS_PC.READ_OWNED_STOCK_APPLY_LIST
        } // 领用申请
      ]
    }
  },
  methods: {
    onSetRole (row) {
      this.roleDataDialog = row
      this.isShowRoleSetDialog = true
    },
    /**
     * 列举角色
     */
    listRoles: function () {
      roleDefineApi.listRoles()
        .then(data => {
          this.roles = data

          // 默认选中第一个，并查询菜单
          if (!data) {
            return
          }
          this.selectedRoleId = data[0].id
          this.listMenus()
        })
    },

    /**
    * 列举角色对应的视图权限
    */
    listMenus () {
      // 角色 & 客户端都选中时，允许查询
      if (!(this.selectedRoleId && this.tab)) {
        return
      }
      // 表格开始加载
      this.isTableLoading = true
      // 从状态中获取租户Id
      const tenantId = this.userInfo.tenant_id
      // 系统业务权限列表

      let bussinessPermisions = null

      let permissionList = []

      if (this.tab === 'pc') {
        // 获取pc端视图权限列表
        bussinessPermisions = roleMenuApi.getBusinessPermission(this.selectedRoleId, this.tab)
      } else if (this.tab === 'mobile') {
        // 获取mobile端视图权限列表
        bussinessPermisions = roleMenuApi.getBusinessPermission(this.selectedRoleId, this.tab)
      } else if (this.tab === 'pad') {
        // FIXME 获取pad端视图权限列表，目前没有
        bussinessPermisions = roleMenuApi.getBusinessPermission(this.selectedRoleId, this.tab)
      }

      // 获取租户所购买的所有系统视图
      let companyView = roleMenuApi.getCompanyView(tenantId, this.tab)
      // 获取角色所拥有的租户所购买的系统视图权限映射列表
      let permissionsList = roleMenuApi.getPermissions(this.selectedRoleId, this.tab)
      // 获取数据权限
      let roleData = getRoleData(this.selectedRoleId, this.tab)
      // 三个 promise 均完成后，依据角色菜单关联数据，勾选对应菜单项
      Promise.all([companyView, permissionsList, bussinessPermisions, roleData])
        .then(values => {
          // 租户所购买的所有系统视图Id集合
          let companyView = values[0].data
          // 角色所拥有的租户所购买的系统视图权限映射列表
          let menuIds = values[1].data
          // 角色所拥有的业务权限
          let bussinessPermissions = values[2].data
          // 数据权限
          let roleData = values[3].data
          this.roleMenuData = roleData.reduce((obj, item) => {
            _.set(obj, item.viewPrivilegeId, item)
            return obj
          }, {})
          console.log(this.roleMenuData)
          if (this.tab === 'pc') {
            let menuListPc = this.translatePcPermissions(bussinessPermissions, menuIds)
            // ems=> 120 生产环境隐藏ems
            process.env.COMPILE_ENV === 'prod' && (menuListPc = _.cloneDeep(menuListPc).filter(v => v.menuId !== 120))
            process.env.COMPILE_ENV === 'prod' && (menuListPc = _.cloneDeep(menuListPc).filter(v => v.parentId !== 120))
            // ems=> 120 生产环境隐藏ems
            // 工单报表=> 178 只盛驰显示工单报表
            // process.env.COMPILE_ENV === 'test' && this.userInfo.tenant_id !== '1231749700063993858' && (menuListPc = _.cloneDeep(menuListPc).filter(v => v.menuId !== 183))

            // process.env.COMPILE_ENV === 'prod' && (menuListPc = _.cloneDeep(menuListPc).filter(v => v.parentId !== 120))
            permissionList = menuListPc
          } else if (this.tab === 'mobile') {
            permissionList = this.translateMobilePermissions(bussinessPermissions, menuIds)
          } else if (this.tab === 'pad') {
            permissionList = []
          }

          // 将系统中的视图权限列表过滤剩下租户所购买的视图权限列表
          this.menus = permissionList.filter(entry => companyView.includes(entry.menuId))

          // const menuIdAll = menus.filter(item => item.level !== 2).map(v => v.menuId)
          // this.menus = menus.reduce((arr, item) => {
          //   const isPushMenu = item.level === 2 && !(menuIdAll.includes(item.parentId))
          //   if (!isPushMenu) {
          //     arr.push(item)
          //   }
          //   return arr
          // }, [])
          // 将角色拥有的视图权限数据置为true
          this.menus.filter(o => menuIds.includes(o.menuId))
            .forEach(o => {
              o.isChecked = true
            })

          // 结束表格加载
          this.isTableLoading = false
        })
    },

    /**
    * 将枚举中的pc端视图权限数据拼合成组件所需要的数据
    */
    translatePcPermissions (businessPermissions, sysPermissions) {
      const newArr = Object.entries(this.Enums.SYS_PERMISSION)
        .map(entry => {
          let level = null
          let childrenCount = null
          let isBusiness = false
          let businessAuthority = null
          let type = ''
          const businessAuthorityOpt = []
          // let isAll = null
          if (entry[1].type === 'MENU_LEVEL_ONE') {
            level = 0
            type = '目录'
          } else if (entry[1].type === 'PAGE') {
            level = 1
            type = '菜单'
          } else if (entry[1].type === 'BUTTON' || entry[1].type === 'TAB') {
            level = 2
            entry[1].type === 'BUTTON' ? type = '按钮' : type = '标签页'
          }

          // 获取后代数量
          const menuId = entry[1].value
          childrenCount = Object.entries(this.Enums.SYS_PERMISSION).filter(
            entry => entry[1].parentId === menuId).length

          // 获取该页有无业务权限
          const businessPermission = _.cloneDeep(this.pcBusinessAuthority).find(v => v.page === menuId)
          if (!_.isNil(businessPermission)) {
            // 为业务权限
            isBusiness = true
            businessAuthorityOpt.push({
              value: businessPermission.all.value,
              label: businessPermission.all.desc
            }, {
              value: businessPermission.owned.value,
              label: businessPermission.owned.desc
            })
            // 业务权限数据源
            let newOpt = businessAuthorityOpt.map(o => {
              return o.value
            })
            // 若接口返回业务权限按接口返回的权限显示，若返回为空默认个人的权限
            newOpt.filter(function (v) { return businessPermissions.indexOf(v) > -1 }).length > 0
              ? businessAuthority = newOpt.filter(function (v) { return businessPermissions.indexOf(v) > -1 })[0]
              : businessAuthority = businessPermission.owned.value
          }

          return {
            menuId: entry[1].value,
            name: entry[1].desc,
            parentId: entry[1].parentId,
            show: true,
            expand: true,
            isChecked: false,
            level: level,
            type: type,
            roleMenuData: this.roleMenuData[entry[1].value],
            roleDataItem: this.roleMenuData[entry[1].value] ? this.roleMenuData[entry[1].value].description : '',
            isAll: this.roleMenuData[entry[1].value] ? this.roleMenuData[entry[1].value].isAll : '',
            parentName: entry[1].parentName,
            terminalType: 'pc',
            childrenCount: childrenCount,
            isBusiness: isBusiness,
            businessAuthorityOpt: businessAuthorityOpt,
            businessAuthority: businessAuthority
          }
        })
      return newArr
    },

    /**
     * 将枚举中的mobile端视图权限数据拼合成组件所需要的数据
     */
    translateMobilePermissions (businessPermissions, sysPermissions) {
      const newArr = Object.entries(this.Enums.SYS_PERMISSIONS_MOBILE)
        .map(entry => {
          let childrenCount = null
          let isBusiness = false
          const businessAuthorityOpt = []
          let businessAuthority = null
          let type = ''
          if (entry[1].level === 0) {
            type = '目录'
          } else if (entry[1].level === 1 || entry[1].level === 2 || entry[1].level === 3) {
            type = '功能'
          }

          // 获取后代数量
          const menuId = entry[1].value
          childrenCount = Object.entries(this.Enums.SYS_PERMISSIONS_MOBILE).filter(
            entry => entry[1].parentId === menuId).length

          // 获取该页有无业务权限
          const businessPermission = _.cloneDeep(this.mBusinessAuthority).find(v => v.page === menuId)
          if (!_.isNil(businessPermission)) {
            // 为业务权限
            isBusiness = true
            businessAuthorityOpt.push({
              value: businessPermission.all.value,
              label: businessPermission.all.desc
            }, {
              value: businessPermission.owned.value,
              label: businessPermission.owned.desc
            })
            // 业务权限数据源
            let newOpt = businessAuthorityOpt.map(o => {
              return o.value
            })
            // 若接口返回业务权限按接口返回的权限显示，若返回为空默认个人的权限
            newOpt.filter(function (v) { return businessPermissions.indexOf(v) > -1 }).length > 0
              ? businessAuthority = newOpt.filter(function (v) { return businessPermissions.indexOf(v) > -1 })[0]
              : businessAuthority = businessPermission.owned.value
          }

          return {
            menuId: entry[1].value,
            name: entry[1].desc,
            parentId: entry[1].parentId,
            show: true,
            expand: true,
            isChecked: false,
            level: entry[1].level,
            roleMenuData: this.roleMenuData[entry[1].value],
            roleDataItem: this.roleMenuData[entry[1].value] ? this.roleMenuData[entry[1].value].description : '',
            isAll: this.roleMenuData[entry[1].value] ? this.roleMenuData[entry[1].value].isAll : '',
            type: type,
            parentName: entry[1].parentName,
            terminalType: 'mobile',
            childrenCount: childrenCount,
            isBusiness: isBusiness,
            businessAuthorityOpt: businessAuthorityOpt,
            businessAuthority: businessAuthority
          }
        })
      return newArr
    },

    /**
     * on 角色被点击
     * @param id
     */
    onRoleClick: function (id) {
      this.selectedRoleId = id
      this.listMenus()
    },

    /**
     * on toggle 菜单
     * @param menu 菜单对象
     */
    onMenuToggle: function (menu) {
      menu.isChecked ? this.onCheckMenu(menu) : this.onUncheckMenu(menu)
    },

    /**
     * on 开启菜单权限
     *
     * check 菜单时，同时 check 其所有祖先菜单
     *
     * @param menu 菜单对象
     */
    onCheckMenu: function (menu) {
      // 获取所有 unchecked 祖先、子孙菜单
      let ancestorMenus = this.listAncestorMenus(menu).filter(o => !o.isChecked)
      let descendantMenus = this.listDescendantMenus(menu).filter(o => !o.isChecked)
      let otherMenus = [...ancestorMenus, ...descendantMenus]

      // check 祖先 & 子孙菜单们
      otherMenus.forEach(o => {
        o.isChecked = true
      })
    },

    /**
     * on 关闭菜单权限
     *
     * uncheck 菜单时，同时 uncheck 所有后代菜单
     *
     * 若兄弟菜单均为 uncheck 状态，则同时 uncheck 其父级菜单
     *
     * @param menu 菜单对象
     */
    onUncheckMenu: function (menu) {
      console.log(menu)
      // 获取所有兄弟菜单
      let noneChecked = this.listSiblingMenus(menu).every(o => !o.isChecked)
      console.log(noneChecked)
      if (this.tab === 'pc' ? noneChecked && menu.level > 0 : noneChecked && menu.level > 1) {
        // 若兄弟菜单全部未勾选、且有父级菜单
        // 则不再取消勾选当前菜单，转为取消勾选父级菜单
        // 强制勾选本级菜单，否则转到父级后，无法取消勾选本级菜单
        if (menu.level === 1) {
          menu.isChecked = true
          this.listAncestorMenus(menu, true).forEach(o => this.onUncheckMenu(o))
        } else {
          menu.isChecked = false
        }
        return
      }

      // uncheck 时，同时 uncheck 所有后代
      // 获取已勾选的后代菜单 list
      let checkedDescendantMenus = this.listDescendantMenus(menu).filter(o => o.isChecked)

      // 取消勾选
      menu.isChecked = false
      checkedDescendantMenus.forEach(o => {
        o.isChecked = false
      })
    },

    /**
    * 保存用户角色视图权限
    */
    savePermissions () {
      let permissionIds = this.menus.filter(o => o.isChecked).map(i => {
        return i.menuId
      })
      console.log(this.menus.filter(o => o.isBusiness))
      // let businessPermissionIds = this.menus.filter(o => o.isBusiness).map(i => {
      //   return i.businessAuthority
      // })

      let promisePermissions = roleMenuApi.savePermission(this.selectedRoleId, this.tab, permissionIds)
      // let promisebusinessPermissions = roleMenuApi.saveBusinessPermission(this.selectedRoleId, this.tab, businessPermissionIds)
      Promise.all([promisePermissions]).then(res => {
        this.listMenus()
        this.$message.success('保存成功')
      })
    },

    /**
     * 切换展开状态
     * @param node
     */
    toggleExpansion (node) {
      node.expand ? this.collapseMenu(node) : this.expandMenu(node)
    },

    /**
     * 展开菜单
     *
     * @param menu 菜单节点
     */
    expandMenu (menu) {
      menu.expand = true

      this.listDescendantMenus(menu, true).forEach(subMenu => {
        subMenu.show = true
      })
    },

    /**
     * 折叠菜单
     *
     * 折叠菜单的同时，折叠所有后代菜单
     *
     * @param menu 菜单节点
     */
    collapseMenu (menu) {
      menu.expand = false

      // 隐藏并折叠所有后代 menu
      this.listDescendantMenus(menu).forEach(subMenu => {
        subMenu.show = false
        subMenu.expand = false
      })
    },

    /**
     * 列举兄弟菜单节点
     * @param menu 菜单节点
     * @returns {Array<{}>} 兄弟菜单节点数组
     */
    listSiblingMenus: function (menu) {
      return this.menus.filter(o => o.parentId === menu.parentId && o.menuId !== menu.menuId)
    },

    /**
     * 列举祖先菜单节点
     * @param menu 菜单节点
     * @param [parentOnly=false] {Boolean} true = 仅获取父级菜单节点，false = 获取所有祖先菜单节点
     * @returns {Array<{}>} 祖先菜单节点数组
     */
    listAncestorMenus: function (menu, parentOnly = false) {
      if (menu.level === 0) {
        // 若当前 node 已经位于顶级，则不存在父级 node
        // 故直接返回空数组
        return []
      }

      let parentNode = this.menus.find(o => o.menuId === menu.parentId)

      if (parentOnly) {
        // 若仅获取父级，则直接返回父级
        return [parentNode]
      }

      return [...this.listAncestorMenus(parentNode), parentNode]
    },

    /**
     * 列举后代菜单节点
     * @param menu 菜单节点
     * @param [childrenOnly=false] {Boolean} true = 仅获取子级菜单节点，false = 获取所有后代菜单节点
     * @returns {Array<{}>} 后代菜单节点数组
     */
    listDescendantMenus: function (menu, childrenOnly = false) {
      if (menu.childrenCount === 0) {
        // 若当前 node 没有子级，则直接返回空数组
        return []
      }

      // 获取子菜单们
      let childNodes = this.menus.filter(o => o.parentId === menu.menuId)

      if (childrenOnly) {
        // 若仅获取子级，则直接返回子菜单们
        return childNodes
      }

      // 获取子菜单们的子菜单们
      let childNodesChildren = childNodes
        .map(childNode => this.listDescendantMenus(childNode))
        .flatMap(o => o)

      return [...childNodes, ...childNodesChildren]
    }
  },
  created () {
    // 初始化埋点数据
    this.listRoles()
  },
  watch: {
    // 选中的 tab
    tab: function () {
      // 重新列举菜单
      this.listMenus()
    }
  }
}
</script>

<style scoped lang="stylus">
  .role-menu {
    .box {
      display flex
      flex-direction column
      width 100%
      min-width 250px
      border-radius 6px
      overflow hidden
      height 100%

      &.left {
        .box-content {
          flex 1
          padding-bottom 20px

          .role-item {
            padding-left 30px
            font-size 16px

            &.activated {
              background #cfd6fe
              color $primary
            }

            &:hover {
              background #e8ebff

              /deep/ .q-focus-helper {
                display none
              }
            }
          }

          .q-separator {
            margin-left 20px
            width calc(100% - 40px)
          }
        }
      }

      &.right {
        .box-content {
          display flex
          flex-direction column
          flex 1
          padding-top 5px
        }
      }
    }
  }
  >>>.q-tab{
    min-height 40px
  }
</style>
